package com.xtaller.sdboot.config;

import com.xtaller.sdboot.util.CacheUtil;
import com.xtaller.sdboot.utils.annotation.*;
import com.xtaller.sdboot.utils.bean.PermissionModel;
import lombok.var;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;

import java.util.*;

/**
 * @author : Taller
 * @date : 2020/2/7 23:44
 * @Description : 生成权限表
 */
@Component
public class AssemblyAuth {
    private final String[] BASE_CONTROLLERS = {
            "springfox.documentation.swagger.web.ApiResourceController",
            "org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController"
            //"com.xtaller.sdboot.utils.base.BaseController"
    };
    @Value("${spring.application.name}")
    private String serviceName;

    @Autowired private ApplicationContext applicationContext;
    @Autowired private CacheUtil cacheUtil;

    @Autowired
    public void AssemblyAuth(){
        AbstractHandlerMethodMapping<RequestMappingInfo> objHandlerMethodMapping =
                (AbstractHandlerMethodMapping<RequestMappingInfo>)applicationContext.getBean("requestMappingHandlerMapping");
        Map<RequestMappingInfo, HandlerMethod> map = objHandlerMethodMapping.getHandlerMethods();

        List<PermissionModel> list = new ArrayList<>();
        Set<String> set = new HashSet<>(Arrays.asList(BASE_CONTROLLERS));
        for (Map.Entry<RequestMappingInfo, HandlerMethod> m : map.entrySet()) {
            var pm = new PermissionModel();

            RequestMappingInfo info = m.getKey();
            HandlerMethod method = m.getValue();
            PatternsRequestCondition p = info.getPatternsCondition();
            for (String url : p.getPatterns()) {
                pm.setUrl(url);
            }
            var className = method.getMethod().getDeclaringClass().getName();
            if (!set.contains(className)) {
                // 只有有注解的才能进入权限控制
                var hasPermission = 0;
                // 类名
                pm.setClassName(className);
                // 方法名
                pm.setFunction(method.getMethod().getName());

                // Common公共注解
                Common common = method.getMethod().getAnnotation(Common.class);
                if (common != null) {
                    hasPermission += 1;
                    pm.setIsCommon(true);
                }
                // 登录注解
                Login login = method.getMethod().getAnnotation(Login.class);
                if (login != null) {
                    hasPermission += 1;
                    pm.setIsLogin(true);
                }
                // token注解
                Token token = method.getMethod().getAnnotation(Token.class);
                if (token != null) {
                    hasPermission += 1;
                    pm.setIsToken(true);
                }
                // Permission 注解
                Permission permission = method.getMethod().getAnnotation(Permission.class);
                if (permission != null) {
                    hasPermission += 1;
                    pm.setIsToken(true);
                    pm.setIsPermission(true);
                    pm.setPermission(permission.authorities());
                }
                // Subsystem 子系统权限
                App subsystem = method.getMethod().getAnnotation(App.class);
                if (subsystem != null) {
                    hasPermission += 1;
                    pm.setIsToken(true);
                    pm.setIsApp(true);
                }

                RequestMethodsRequestCondition methodsCondition = info.getMethodsCondition();
                for (RequestMethod requestMethod : methodsCondition.getMethods()) {
                    pm.setMethod(requestMethod.toString().toUpperCase());
                }
                if(hasPermission > 0) {
                    list.add(pm);
                }
            }
        }

        var key = serviceName + "-permission";

        if(list.size() > 0){
            // 加入到内存缓存中
            cacheUtil.set(key, list);
        }
    }
}
